package com.mask.token.service;

import com.mask.token.config.MaskTokenProperties;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * JWT密钥管理服务
 * 提供安全的密钥生成、验证和管理功能
 *
 * @author mask
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(name = "mask.token.key-management.enabled", havingValue = "true", matchIfMissing = false)
public class MaskTokenKeyService {

    private final MaskTokenProperties properties;
    private SecretKey cachedSigningKey;

    /**
     * 获取签名密钥
     * 使用缓存机制提高性能
     */
    public SecretKey getSigningKey() {
        if (cachedSigningKey == null) {
            cachedSigningKey = generateSigningKey();
        }
        return cachedSigningKey;
    }

    /**
     * 生成签名密钥
     */
    private SecretKey generateSigningKey() {
        try {
            String secret = properties.getSecret();
            
            // 验证密钥长度
            if (secret == null || secret.trim().isEmpty()) {
                throw new IllegalArgumentException("JWT密钥不能为空");
            }
            
            // 如果密钥长度不足，使用SHA-256哈希扩展
            byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
            if (keyBytes.length < 32) {
                keyBytes = extendKey(keyBytes, 32);
                log.warn("JWT密钥长度不足，已自动扩展到32字节");
            } else if (keyBytes.length > 64) {
                // 如果密钥过长，截取前64字节
                byte[] truncatedKey = new byte[64];
                System.arraycopy(keyBytes, 0, truncatedKey, 0, 64);
                keyBytes = truncatedKey;
                log.warn("JWT密钥长度过长，已截取前64字节");
            }
            
            SecretKey key = new SecretKeySpec(keyBytes, SignatureAlgorithm.HS512.getJcaName());
            
            // 记录密钥信息（不记录实际密钥值）
            log.info("JWT密钥已生成，长度: {} 字节", keyBytes.length);
            
            return key;
            
        } catch (Exception e) {
            log.error("生成JWT密钥失败", e);
            throw new RuntimeException("生成JWT密钥失败", e);
        }
    }

    /**
     * 扩展密钥到指定长度
     */
    private byte[] extendKey(byte[] originalKey, int targetLength) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] extendedKey = new byte[targetLength];
            int currentLength = 0;
            
            // 使用原始密钥作为种子，通过多次哈希扩展
            byte[] seed = originalKey;
            while (currentLength < targetLength) {
                seed = digest.digest(seed);
                int copyLength = Math.min(seed.length, targetLength - currentLength);
                System.arraycopy(seed, 0, extendedKey, currentLength, copyLength);
                currentLength += copyLength;
            }
            
            return extendedKey;
            
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-256算法不可用", e);
            // 如果SHA-256不可用，使用简单的重复填充
            byte[] extendedKey = new byte[targetLength];
            for (int i = 0; i < targetLength; i++) {
                extendedKey[i] = originalKey[i % originalKey.length];
            }
            return extendedKey;
        }
    }

    /**
     * 验证密钥强度
     */
    public boolean validateKeyStrength() {
        try {
            String secret = properties.getSecret();
            if (secret == null || secret.trim().isEmpty()) {
                log.error("JWT密钥为空");
                return false;
            }
            
            byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
            
            // 检查密钥长度
            if (keyBytes.length < 32) {
                log.warn("JWT密钥长度不足，建议至少32字节，当前: {} 字节", keyBytes.length);
                return false;
            }
            
            // 检查密钥复杂度
            if (isSimpleKey(secret)) {
                log.warn("JWT密钥过于简单，建议使用复杂的密钥");
                return false;
            }
            
            log.info("JWT密钥强度验证通过");
            return true;
            
        } catch (Exception e) {
            log.error("验证密钥强度失败", e);
            return false;
        }
    }

    /**
     * 检查是否为简单密钥
     */
    private boolean isSimpleKey(String secret) {
        // 检查是否为常见弱密钥
        String[] weakKeys = {
            "secret", "password", "123456", "admin", "test",
            "mask-token-secret-key-2024", "your-secret-key"
        };
        
        for (String weakKey : weakKeys) {
            if (secret.equals(weakKey) || secret.equalsIgnoreCase(weakKey)) {
                return true;
            }
        }
        
        // 检查是否只包含数字
        if (secret.matches("\\d+")) {
            return true;
        }
        
        // 检查是否只包含字母
        if (secret.matches("[a-zA-Z]+")) {
            return true;
        }
        
        return false;
    }

    /**
     * 生成安全的随机密钥
     */
    public String generateRandomKey() {
        try {
            // 使用系统随机数生成器生成32字节的随机密钥
            byte[] randomBytes = new byte[32];
            java.security.SecureRandom.getInstanceStrong().nextBytes(randomBytes);
            
            // 转换为Base64编码的字符串
            String randomKey = Base64.getEncoder().encodeToString(randomBytes);
            
            log.info("已生成随机JWT密钥，长度: {} 字符", randomKey.length());
            return randomKey;
            
        } catch (Exception e) {
            log.error("生成随机密钥失败", e);
            throw new RuntimeException("生成随机密钥失败", e);
        }
    }

    /**
     * 清除缓存的密钥
     */
    public void clearCachedKey() {
        cachedSigningKey = null;
        log.debug("已清除缓存的JWT密钥");
    }

    /**
     * 获取密钥信息（用于调试，不包含实际密钥值）
     */
    public KeyInfo getKeyInfo() {
        KeyInfo info = new KeyInfo();
        info.setKeyLength(properties.getSecret().length());
        info.setKeyStrength(validateKeyStrength());
        info.setAlgorithm(SignatureAlgorithm.HS512.getValue());
        info.setCached(cachedSigningKey != null);
        
        return info;
    }

    /**
     * 密钥信息
     */
    public static class KeyInfo {
        private int keyLength;
        private boolean keyStrength;
        private String algorithm;
        private boolean cached;

        // Getters and Setters
        public int getKeyLength() { return keyLength; }
        public void setKeyLength(int keyLength) { this.keyLength = keyLength; }
        public boolean isKeyStrength() { return keyStrength; }
        public void setKeyStrength(boolean keyStrength) { this.keyStrength = keyStrength; }
        public String getAlgorithm() { return algorithm; }
        public void setAlgorithm(String algorithm) { this.algorithm = algorithm; }
        public boolean isCached() { return cached; }
        public void setCached(boolean cached) { this.cached = cached; }
    }
}
